package com.rongxunwu.netty.learning;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * TODO
 *
 * @author WuRongXun
 * @version 1.0
 * @date 2021/11/1 20:39
 */
public class NioServer {
    public static void main(String[] args) throws IOException {
        //创建ServerSocketChannel ->ServerSocket
        ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();

        //得到一个Selector
        Selector selector = Selector.open();
        //绑定端口8080，在服务器监听
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));

        //设置非阻塞
        serverSocketChannel.configureBlocking(false);
        //把serversoketChannel 注册到selector 关心 事件未OP_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true){
            //设置等待一秒，如果没有事件发生，返回
            if (selector.select(2000)==0){
                System.out.printf("服务器等待2秒，无连接\n");
                continue;
            }
            //如果返回的>0,就获取相关的selecttionKey 集合
            //1. 如果返回大于0，表示已经获取到关注的事件
            //2. selector.selectedKey() 返回关注事件的集合
            //  通过selectedKeys 反向获取通道
            Set<SelectionKey> selectionKeys=selector.selectedKeys();
            //遍历Set<SelectionKey> 使用迭代器
            Iterator<SelectionKey> keyIterator=selectionKeys.iterator();

            while (keyIterator.hasNext()){
                //获取selectionKey
                SelectionKey key=keyIterator.next();
                //根据key 对应是通道发生的事件做相应处理
                if (key.isAcceptable()){
                    //该客户端生成一个SocketChannel；
                    SocketChannel socketChannel=serverSocketChannel.accept();
                    System.out.printf("客户端连接成功，生成一个socketChannel "+socketChannel.hashCode()+"\n");

                    //将socketChannel 设置为非阻塞
                    socketChannel.configureBlocking(false);

                    //将SocketChannel 注册到 selector,关联事件OP_READ,同事给socketChannel 关联一个Buffer
                    socketChannel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                if (key.isReadable()){
                    //通过key 反向获取channel
                    SocketChannel channel=(SocketChannel)key.channel();
                    //获取该channel 关联的buffer
                    ByteBuffer buffer= (ByteBuffer) key.attachment();
                    channel.read(buffer);
                    System.out.printf("\nfrom 客户端："+new String(buffer.array()));
                }
                //手动从集合中移动当前的selectionKey, 防止重复操作
                keyIterator.remove();
            }
        }
    }
}
